package v1

import (
	"gitee.com/enzolwb/my-web-scaffold/models"
	"gitee.com/enzolwb/my-web-scaffold/pkg/app"
	"gitee.com/enzolwb/my-web-scaffold/pkg/app/validation"
	"gitee.com/enzolwb/my-web-scaffold/pkg/ecode"
	"gitee.com/enzolwb/my-web-scaffold/pkg/setting"
	"gitee.com/enzolwb/my-web-scaffold/service/article_service"
	"gitee.com/enzolwb/my-web-scaffold/service/tag_service"
	"github.com/EnzoLwb/cuslog"
	"github.com/gin-gonic/gin"
	"github.com/unknwon/com"
	"time"
)

// @Summary Get a single article
// @Produce  json
// @Param id path int true "ID"
// @Success 200 {object} app.ResponseJSON
// @Failure 500 {object} app.ResponseJSON
// @Router /api/v1/articles/{id} [get]
func GetArticle(c *gin.Context) {
	id := com.StrTo(c.Param("id")).MustInt()
	articleService := article_service.Article{ID: id}
	exists, err := articleService.ExistByID()
	if err != nil {
		app.Response(c, ecode.ErrCheckArticleFail)
		return
	}
	if !exists {
		app.Response(c, ecode.ErrCheckExistArticleFail)
		return
	}

	article, err := articleService.Get()
	if err != nil {
		app.Response(c, ecode.ErrCheckArticleFail)
		return
	}

	app.Response(c, ecode.Ok, article)
}

//Articles 可选参数的实例 传参可选 不传不验证，重点是结构体中为指针类型，并且在赋予默认值时需要new(Type),原因是需要开辟一块内存空间 指明值类型的类型
type Articles struct {
	State *int `form:"state" binding:"omitempty,min=0,max=1" comment:"状态"`
	TagId *int `form:"tag_id" binding:"omitempty,min=1" comment:"标签"`
}

// @Summary Get multiple articles
// @Produce  json
// @Param tag_id body int false "TagID"
// @Param state body int false "State"
// @Param created_by body int false "CreatedBy"
// @Success 200 {object} app.ResponseJSON
// @Failure 500 {object} app.ResponseJSON
// @Router /api/v1/articles [get]
func GetArticles(c *gin.Context) {
	//默认值
	var a Articles
	var tagId = -1
	var state = -1

	if err := validation.BindValidParams(c, &a); err != nil {
		return
	}

	if a.State == nil {
		a.State = new(int)
		*a.State = state
	}
	if a.TagId == nil {
		a.TagId = new(int)
		*a.TagId = tagId
	}

	articleService := article_service.Article{
		TagID:    tagId,
		State:    state,
		PageNum:  app.GetPage(c),
		PageSize: setting.AppSetting.PageSize,
	}

	total, err := articleService.Count()
	if err != nil {
		app.Response(c, ecode.ErrArticleCount, nil)
		return
	}

	articles, err := articleService.GetAll()
	if err != nil {
		app.Response(c, ecode.ErrCheckArticlesFail, nil)
		return
	}

	data := make(map[string]interface{})
	data["lists"] = articles
	data["total"] = total

	//测试下日志
	cuslog.Info("获取文章成功", cuslog.Int("total", total),
		cuslog.String("current_time", time.Now().Format("2006-01-02 15:04:05")))
	cuslog.Warn("获取文章成功", cuslog.Int("total", total),
		cuslog.String("current_time", time.Now().Format("2006-01-02 15:04:05")))
	app.Response(c, ecode.Ok, data)
}

type AddArticleForm struct {
	TagID         int    `form:"tag_id" binding:"required,min=1"`
	Title         string `form:"title" binding:"required,lt=20"`
	Desc          string `form:"desc" binding:"required"`
	Content       string `form:"content" binding:"required"`
	CreatedBy     string `form:"created_by" binding:"required"`
	CoverImageUrl string `form:"cover_image_url" binding:"required"`
	State         int    `form:"state" binding:"min=0,max=1"`
}

// @Summary Add article
// @Produce  json
// @Param tag_id body int true "TagID"
// @Param title body string true "Title"
// @Param desc body string true "Desc"
// @Param content body string true "Content"
// @Param created_by body string true "CreatedBy"
// @Param state body int true "State"
// @Success 200 {object} app.ResponseJSON
// @Failure 500 {object} app.ResponseJSON
// @Router /api/v1/articles [post]
// AddArticle 新增文章
func AddArticle(c *gin.Context) {
	var (
		form AddArticleForm
		err  error
	)

	if err = validation.BindValidParams(c, &form); err != nil {
		return
	}

	tagService := tag_service.Tag{ID: form.TagID}
	exists, err := tagService.ExistByID()
	if err != nil {
		app.Response(c, ecode.ErrCheckTag)
		return
	}

	if !exists {
		app.Response(c, ecode.ErrExistTag)
		return
	}

	articleService := article_service.Article{
		TagID:         form.TagID,
		Title:         form.Title,
		Desc:          form.Desc,
		Content:       form.Content,
		CoverImageUrl: form.CoverImageUrl,
		State:         form.State,
		CreatedBy:     form.CreatedBy,
	}
	if err := articleService.Add(); err != nil {
		app.Response(c, ecode.ErrAddArticlesFail)
		return
	}

	app.Response(c, ecode.Ok)
}

type EditArticleForm struct {
	ID            int    `form:"id" binding:"required,min=1"`
	TagID         int    `form:"tag_id" binding:"required,min=1"`
	Title         string `form:"title" binding:"required,lt=20"`
	Desc          string `form:"desc" binding:"required"`
	Content       string `form:"content" binding:"required"`
	ModifiedBy    string `form:"modified_by" binding:""`
	CoverImageUrl string `form:"cover_image_url" binding:""`
	State         *int   `form:"state" binding:""`
}

// @Summary Update article
// @Produce  json
// @Param id path int true "ID"
// @Param tag_id body string false "TagID"
// @Param title body string false "Title"
// @Param desc body string false "Desc"
// @Param content body string false "Content"
// @Param modified_by body string true "ModifiedBy"
// @Param state body int false "State"
// @Success 200 {object} app.ResponseJSON
// @Failure 500 {object} app.ResponseJSON
// @Router /api/v1/articles/{id} [put]
func EditArticle(c *gin.Context) {
	var (
		form  EditArticleForm
		state int
	)
	if err := validation.BindValidParams(c, &form); err != nil {
		return
	}
	state = -1
	if form.State == nil {
		form.State = new(int)
		*form.State = state
	}
	articleService := article_service.Article{ID: form.ID}
	exists, err := articleService.ExistByID()
	if err != nil {
		app.Response(c, ecode.ErrCheckArticleFail)
		return
	}
	if !exists {
		app.Response(c, ecode.ErrCheckExistArticleFail)
		return
	}

	data := make(map[string]interface{})
	data["title"] = form.Title
	data["cover_image_url"] = form.CoverImageUrl
	data["tag_id"] = form.TagID
	data["desc"] = form.Desc
	data["content"] = form.Content
	data["state"] = form.State
	data["modified_by"] = form.ModifiedBy

	err = models.EditArticle(form.ID, data)
	if err != nil {
		app.Response(c, ecode.ErrEditArticlesFail)
		return
	}
	app.Response(c, ecode.Ok)
}

// @Summary Delete article
// @Produce  json
// @Param id path int true "ID"
// @Success 200 {object} app.ResponseJSON
// @Failure 500 {object} app.ResponseJSON
// @Router /api/v1/articles/{id} [delete]
func DeleteArticle(c *gin.Context) {
	id := com.StrTo(c.Param("id")).MustInt()

	articleService := article_service.Article{ID: id}
	exists, err := articleService.ExistByID()
	if err != nil {
		app.Response(c, ecode.ErrCheckArticleFail)
		return
	}
	if !exists {
		app.Response(c, ecode.ErrCheckExistArticleFail)
		return
	}

	err = articleService.Delete()
	if err != nil {
		app.Response(c, ecode.ErrDelArticleFail)
		return
	}

	app.Response(c, ecode.Ok)
}
